package org.abacus.client.ui.access;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.abacus.client.config.layout.GridDataConfig;
import org.abacus.client.config.layout.GridLayoutConfig;
import org.abacus.client.config.layout.LayoutConfig;
import org.abacus.client.config.layout.LayoutConfigType;
import org.abacus.client.config.layout.LayoutDataConfig;
import org.abacus.client.config.widgets.ButtonConfig;
import org.abacus.client.config.widgets.ComboConfig;
import org.abacus.client.config.widgets.CompositeConfig;
import org.abacus.client.config.widgets.GroupConfig;
import org.abacus.client.config.widgets.LabelConfig;
import org.abacus.client.config.widgets.ListConfig;
import org.abacus.client.config.widgets.ShellConfig;
import org.abacus.client.config.widgets.TextConfig;
import org.abacus.client.config.widgets.ViewConfig;
import org.abacus.client.config.widgets.ViewConfigType;
import org.abacus.client.dao.config.widgets.ViewConfigDao;
import org.abacus.client.ui.control.widgets.LButton;
import org.abacus.client.ui.control.widgets.LCombo;
import org.abacus.client.ui.control.widgets.LComposite;
import org.abacus.client.ui.control.widgets.LDialog;
import org.abacus.client.ui.control.widgets.LGroup;
import org.abacus.client.ui.control.widgets.LLabel;
import org.abacus.client.ui.control.widgets.LList;
import org.abacus.client.ui.control.widgets.LListener;
import org.abacus.client.ui.control.widgets.LShell;
import org.abacus.client.ui.control.widgets.LText;
import org.abacus.client.ui.control.widgets.WidgetProvider;
import org.abacus.dao.DaoFactory;
import org.abacus.platform.core.dao.TransactionStrategy;
import org.abacus.platform.core.util.GUID;
import org.abacus.platform.util.CollectionUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.junit.Test;

public class AccessDataFactoryImpl extends AccessDataFactory {
	ViewConfigDao viewConfigDao = DaoFactory.getInstance(ViewConfigDao.class);
	TransactionStrategy transactionStrategy = DaoFactory.getTransactionStrategy();

	@Test
	public void testGridDataConfig() {
		DaoFactory.getTransactionStrategy().begin();
		GridDataConfig vc = new GridDataConfig();
		vc.setId(GUID.value());
		viewConfigDao.saveOrUpdate(vc);
		DaoFactory.getTransactionStrategy().commit();
	}

	@Test
	public void testGridLayoutConfig() {
		DaoFactory.getTransactionStrategy().begin();
		GridLayoutConfig vc = new GridLayoutConfig();
		vc.setId(GUID.value());
		viewConfigDao.saveOrUpdate(vc);
		DaoFactory.getTransactionStrategy().commit();
	}

	@Override
	public AccessData createAccessData(String id, WidgetProvider widgetProvider) {
		try {
			transactionStrategy.begin();
			ViewConfig viewConfig = viewConfigDao.findById(id);
			if (null == viewConfig) {
				return null;
			}
			AccessData ad = createAccessData(viewConfig, widgetProvider.getWidget());
			transactionStrategy.commit();
			return ad;
		} catch (Exception e) {
			e.printStackTrace();
			transactionStrategy.rollback();
		}
		return null;
	}

	@Override
	public AccessData createAccessData(String id, Widget widget) {
		ViewConfig viewConfig = viewConfigDao.findById(id);
		if (null == viewConfig) {
			return null;
		}
		AccessData ad = createAccessData(viewConfig, widget);
		return ad;
	}

	@Override
	public AccessData createAccessData(ViewConfig viewConfig, Widget widget) {
		AccessData ad = createAccessData(viewConfig.getViewConfigType(), viewConfig.getStyle(), widget);
		if (null == ad) {
			return null;
		}
		ad.setId(viewConfig.getId());

		if (null != viewConfig.getSelectionListener()) {
			try {
				LListener lListener = (LListener) Class.forName(viewConfig.getSelectionListener()).newInstance();
				lListener.setAccessData(ad);
				ad.getControl().addListener(SWT.Selection, lListener);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}

		if (null != viewConfig.getDisposeListener()) {
			try {
				LListener lListener = (LListener) Class.forName(viewConfig.getDisposeListener()).newInstance();
				lListener.setAccessData(ad);
				ad.getControl().addListener(SWT.Dispose, lListener);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		if (null != viewConfig.getLayoutConfig()) {
			if (ad.getControl() instanceof Composite) {
				((Composite) ad.getControl()).setLayout(getLayout(viewConfig.getLayoutConfig()));
			}
			if (ad.getControl() instanceof Group) {
				((Group) ad.getControl()).setLayout(getLayout(viewConfig.getLayoutConfig()));
			}

			if (ad.getControl() instanceof Shell) {
				((Shell) ad.getControl()).setLayout(getLayout(viewConfig.getLayoutConfig()));
			}
		}
		if (null != viewConfig.getLayoutDataConfig()) {
			ad.getControl().setLayoutData(getLayoutData(viewConfig.getLayoutDataConfig()));
		}
		ad.setValue(viewConfig.getCode());

		java.util.List<ViewConfig> viewConfigs = viewConfigDao.findByProperties(new String[] { "parent.id" },
				new Object[] { viewConfig.getId() }, null, "position");
		if (null != ad && null != ad.getControl()) {
			if (!CollectionUtil.isEmpty(viewConfigs)) {
				AccessData child;
				for (ViewConfig vc : viewConfigs) {
					child = this.createAccessData(vc, ad.getControl());
					if (null != child && null != child.getId()) {
						ad.getChildren().put(ad.getId(), child);
					}
				}
			}
		}
		return ad;
	}

	@Override
	public Layout getLayout(LayoutConfig layoutConfig) {
		if (layoutConfig.getLayoutConfigType() == LayoutConfigType.GRID_LAYOUT_CONFIG) {
			GridLayoutConfig glc = (GridLayoutConfig) layoutConfig;
			GridLayout gridLayout = new GridLayout();
			gridLayout.horizontalSpacing = glc.horizontalSpacing;
			gridLayout.makeColumnsEqualWidth = glc.makeColumnsEqualWidth;
			gridLayout.marginBottom = glc.marginBottom;
			gridLayout.marginHeight = glc.marginHeight;
			gridLayout.marginLeft = glc.marginLeft;
			gridLayout.marginRight = glc.marginRight;
			gridLayout.marginTop = glc.marginTop;
			gridLayout.marginWidth = glc.marginWidth;
			gridLayout.numColumns = glc.numColumns;
			gridLayout.verticalSpacing = glc.verticalSpacing;
			return gridLayout;
		}
		return null;
	}

	@Override
	public Object getLayoutData(LayoutDataConfig layoutDataConfig) {
		if (layoutDataConfig.getLayoutConfigType() == LayoutConfigType.GRID_LAYOUT_CONFIG) {
			GridDataConfig gdc = (GridDataConfig) layoutDataConfig;
			GridData gridData = new GridData(gdc.horizontalAlignment, gdc.verticalAlignment,
					gdc.grabExcessHorizontalSpace, gdc.grabExcessVerticalSpace);
			gridData.exclude = gdc.exclude;
			gridData.grabExcessHorizontalSpace = gdc.grabExcessHorizontalSpace;
			gridData.grabExcessVerticalSpace = gdc.grabExcessVerticalSpace;
			gridData.heightHint = gdc.heightHint;
			gridData.horizontalAlignment = gdc.horizontalAlignment;
			gridData.horizontalIndent = gdc.horizontalIndent;
			gridData.horizontalSpan = gdc.horizontalIndent;
			gridData.minimumHeight = gdc.minimumHeight;
			gridData.minimumWidth = gdc.minimumWidth;
			gridData.verticalAlignment = gdc.verticalAlignment;
			gridData.verticalIndent = gdc.verticalIndent;
			gridData.verticalSpan = gdc.verticalSpan;
			gridData.widthHint = gdc.widthHint;
			return gridData;
		}
		return null;
	}

	@Override
	public GridLayoutConfig getGridLayoutConfig(GridLayout glc) {
		if (null != glc) {
			GridLayoutConfig gridLayout = new GridLayoutConfig();
			gridLayout.horizontalSpacing = glc.horizontalSpacing;
			gridLayout.makeColumnsEqualWidth = glc.makeColumnsEqualWidth;
			gridLayout.marginBottom = glc.marginBottom;
			gridLayout.marginHeight = glc.marginHeight;
			gridLayout.marginLeft = glc.marginLeft;
			gridLayout.marginRight = glc.marginRight;
			gridLayout.marginTop = glc.marginTop;
			gridLayout.marginWidth = glc.marginWidth;
			gridLayout.numColumns = glc.numColumns;
			gridLayout.verticalSpacing = glc.verticalSpacing;
			return gridLayout;
		}
		return null;
	}

	@Override
	public GridDataConfig getGridDataConfig(GridData gdc) {
		if (null != gdc) {
			GridDataConfig gridData = new GridDataConfig();
			gridData.exclude = gdc.exclude;
			gridData.grabExcessHorizontalSpace = gdc.grabExcessHorizontalSpace;
			gridData.grabExcessVerticalSpace = gdc.grabExcessVerticalSpace;
			gridData.heightHint = gdc.heightHint;
			gridData.horizontalAlignment = gdc.horizontalAlignment;
			gridData.horizontalIndent = gdc.horizontalIndent;
			gridData.horizontalSpan = gdc.horizontalIndent;
			gridData.minimumHeight = gdc.minimumHeight;
			gridData.minimumWidth = gdc.minimumWidth;
			gridData.verticalAlignment = gdc.verticalAlignment;
			gridData.verticalIndent = gdc.verticalIndent;
			gridData.verticalSpan = gdc.verticalSpan;
			gridData.widthHint = gdc.widthHint;
			return gridData;
		}
		return null;
	}

	@Override
	public AccessData createAccessData(ViewConfigType viewConfigType, int style, Widget widget) {
		Class<? extends AccessData> clazz = viewConfigTypes.get(viewConfigType);
		if (null == clazz) {
			return null;
		}
		try {
			return clazz.getConstructor(Composite.class, int.class).newInstance(widget, Integer.valueOf(style));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return null;
	}

	static Map<ViewConfigType, Class<? extends AccessData>> viewConfigTypes = new HashMap<ViewConfigType, Class<? extends AccessData>>();

	static {
		viewConfigTypes.put(ViewConfigType.BUTTON_CONFIG, LButton.class);
		viewConfigTypes.put(ViewConfigType.COMBO_CONFIG, LCombo.class);
		viewConfigTypes.put(ViewConfigType.COMPOSITE_CONFIG, LComposite.class);
		viewConfigTypes.put(ViewConfigType.DIALOG_CONFIG, LDialog.class);
		viewConfigTypes.put(ViewConfigType.GROUP_CONFIG, LGroup.class);
		viewConfigTypes.put(ViewConfigType.LIST_CONFIG, LList.class);
		viewConfigTypes.put(ViewConfigType.TEXT_CONFIG, LText.class);
		viewConfigTypes.put(ViewConfigType.LABEL_CONFIG, LLabel.class);
		viewConfigTypes.put(ViewConfigType.SHELL_CONFIG, LShell.class);
	}

	static Map<Class<? extends Widget>, Class<? extends ViewConfig>> widgetsViewConfigType = new HashMap<Class<? extends Widget>, Class<? extends ViewConfig>>();

	static {
		widgetsViewConfigType.put(Button.class, ButtonConfig.class);
		widgetsViewConfigType.put(Combo.class, ComboConfig.class);
		widgetsViewConfigType.put(Composite.class, CompositeConfig.class);
		widgetsViewConfigType.put(Group.class, GroupConfig.class);
		widgetsViewConfigType.put(List.class, ListConfig.class);
		widgetsViewConfigType.put(Text.class, TextConfig.class);
		widgetsViewConfigType.put(Shell.class, ShellConfig.class);
		widgetsViewConfigType.put(Label.class, LabelConfig.class);
	}

	@Override
	public ViewConfig getViewConfig(Class<? extends Widget> keyClazz) {
		if (null == keyClazz) {
			return null;
		}
		Class<? extends ViewConfig> vcClazz = widgetsViewConfigType.get(keyClazz);
		if (null != vcClazz) {
			ViewConfig vc;
			try {
				vc = vcClazz.newInstance();
				vc.setId(GUID.value());
				return vc;
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	@Override
	public void createAccessData(String[] ids, AccessData ad) {
		try {
			transactionStrategy.begin();
			java.util.List<ViewConfig> viewConfigs = viewConfigDao.findByProperties(new String[] { "id" },
					new Object[] { ids }, null, "position");
			if (null != ad && null != ad.getControl()) {
				if (!CollectionUtil.isEmpty(viewConfigs)) {
					AccessData child;
					for (ViewConfig vc : viewConfigs) {
						child = this.createAccessData(vc, ad.getControl());
						if (null != child && null != child.getId()) {
							ad.getChildren().put(ad.getId(), child);
						}
					}
				}
			}
			transactionStrategy.commit();
		} catch (Exception e) {
			e.printStackTrace();
			transactionStrategy.rollback();
		}
	}

	@Override
	public AccessData createAccessData(String id, Display display) {
		try {
			transactionStrategy.begin();
			ViewConfig viewConfig = viewConfigDao.findById(id);
			if (null == viewConfig) {
				return null;
			}
			AccessData ad = createAccessData(viewConfig, display);
			transactionStrategy.commit();
			return ad;
		} catch (Exception e) {
			e.printStackTrace();
			transactionStrategy.rollback();
		}
		return null;
	}

	@Override
	public AccessData createAccessData(ViewConfig viewConfig, Display display) {
		AccessData ad = createAccessData(viewConfig.getViewConfigType(), viewConfig.getStyle(), display);
		if (null == ad) {
			return null;
		}
		ad.setId(viewConfig.getId());

		if (null != viewConfig.getLayoutConfig()) {

			if (ad.getControl() instanceof Shell) {
				Shell shell = (Shell) ad.getControl();
				shell.setLayout(getLayout(viewConfig.getLayoutConfig()));
			}
		}
		if (null != viewConfig.getLayoutDataConfig()) {
			ad.getControl().setLayoutData(getLayoutData(viewConfig.getLayoutDataConfig()));
		}
		ad.setValue(viewConfig.getCode());

		java.util.List<ViewConfig> viewConfigs = viewConfigDao.findByProperties(new String[] { "parent.id" },
				new Object[] { viewConfig.getId() }, null, "position");
		if (null != ad && null != ad.getControl()) {
			if (!CollectionUtil.isEmpty(viewConfigs)) {
				AccessData child;
				for (ViewConfig vc : viewConfigs) {
					child = this.createAccessData(vc, ad.getControl());
					if (null != child && null != child.getId()) {
						ad.getChildren().put(ad.getId(), child);
					}
				}
			}
		}
		if (ad.getControl() instanceof Shell) {
			Shell shell = (Shell) ad.getControl();
			ShellConfig sc = (ShellConfig) viewConfig;
			if (sc.getCenter()) {
				centerShell(shell, sc.getWidth(), sc.getHeight());
			}
		}
		return ad;
	}

	@Override
	public AccessData createAccessData(ViewConfigType viewConfigType, int style, Display display) {
		Class<? extends AccessData> clazz = viewConfigTypes.get(viewConfigType);
		if (null == clazz) {
			return null;
		}
		try {
			return clazz.getConstructor(Display.class, int.class).newInstance(display, Integer.valueOf(style));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return null;
	}
}
